import os
import json
import threading
from datetime import datetime
from flask import Blueprint, request, jsonify, current_app
import traceback
from flask_jwt_extended import jwt_required, get_jwt_identity
from werkzeug.utils import secure_filename
from app.models.decoration_request import DecorationRequest
from app.models.uploaded_file import UploadedFile
from app.services.oss_service import OSSService
from app.services.coze_service import CozeService
from app import db


decoration_bp = Blueprint('decoration', __name__)


def allowed_file(filename):
    """检查文件类型是否允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in current_app.config['ALLOWED_EXTENSIONS']


@decoration_bp.route('/upload', methods=['POST'])
def upload_file():
    """上传户型图文件"""
    try:
        if 'file' not in request.files:
            return jsonify({'error': '没有选择文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'error': '没有选择文件'}), 400
        
        if not allowed_file(file.filename):
            return jsonify({'error': '不支持的文件类型，请上传PNG、JPG、JPEG或BMP格式的图片'}), 400
        
        # 创建临时文件
        filename = secure_filename(file.filename)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        temp_filename = f"{timestamp}_{filename}"
        # 使用绝对路径，避免相对路径在不同工作目录下找不到文件
        upload_base = os.path.abspath(os.path.join(current_app.root_path, '..', current_app.config['UPLOAD_FOLDER']))
        temp_path = os.path.join(upload_base, temp_filename)
        
        # 确保上传目录存在（绝对路径）
        os.makedirs(upload_base, exist_ok=True)
        
        # 保存临时文件
        file.save(temp_path)
        
        try:
            # 上传到OSS
            oss_service = OSSService()
            uploaded_file = oss_service.upload_file(temp_path, filename)
            
            # 删除临时文件（注意：本地回退使用 os.replace 会移动文件，此处需判断存在再删）
            if os.path.exists(temp_path):
                os.remove(temp_path)
            
            return jsonify({
                'success': True,
                'message': '文件上传成功',
                'file': uploaded_file.to_dict()
            })
            
        except Exception as e:
            # 删除临时文件
            if os.path.exists(temp_path):
                os.remove(temp_path)
            raise e
            
    except Exception as e:
        # 打印详细错误堆栈，便于定位 500 的原因
        print('[Upload] Error:', str(e))
        traceback.print_exc()
        return jsonify({'error': f'文件上传失败: {str(e)}'}), 500


@decoration_bp.route('/generate', methods=['POST'])
@jwt_required()
def generate_decoration_plan():
    """生成装修方案"""
    try:
        data = request.get_json() or {}

        # 兼容前端传参：同时支持下划线和驼峰命名
        def pick_value(*keys):
            for key in keys:
                if key in data and data[key] not in (None, ''):
                    return data[key]
            return None

        decoration_style = pick_value('decoration_style', 'decorationStyle')
        room_type = pick_value('room_type', 'roomType')
        decoration_plan = pick_value('decoration_plan', 'decorationPlan')
        budget_min = pick_value('budget_min', 'budgetMin')
        budget_max = pick_value('budget_max', 'budgetMax')
        floor_plan_url = pick_value('floor_plan_url', 'floorPlanUrl') or ''

        # 验证必填字段（更健壮）
        required_map = {
            'decoration_style': decoration_style,
            'room_type': room_type,
            'decoration_plan': decoration_plan,
            'budget_min': budget_min,
            'budget_max': budget_max,
        }
        for field_name, field_value in required_map.items():
            if field_value is None or field_value == '':
                return jsonify({'error': f'缺少必填字段: {field_name}'}), 400
        
        # 获取当前用户ID
        # JWT Subject 必须为字符串，这里转换为整型用户ID
        user_identity = get_jwt_identity()
        try:
            user_id = int(user_identity)
        except (TypeError, ValueError):
            return jsonify({'error': '无效的用户身份'}), 401
        
        # 创建装修请求记录
        timestamp = int(datetime.now().timestamp())
        decoration_request = DecorationRequest(
            user_id=user_id,
            conversation_name=f"装修设计_{timestamp}",
            project_name=f"{room_type}_{decoration_style}风格设计",
            decoration_style=decoration_style,
            room_type=room_type,
            decoration_plan=decoration_plan,
            budget_min=int(budget_min),
            budget_max=int(budget_max),
            floor_plan_url=floor_plan_url,
            status='pending'
        )
        
        db.session.add(decoration_request)
        db.session.commit()
        request_id = decoration_request.id
        
        # 预先捕获真实的 app 对象，避免在线程中访问 current_app 触发上下文错误
        app_obj = current_app._get_current_object()

        # 异步处理装修方案生成（在线程中开启独立的应用上下文与会话）
        def process_decoration(req_id):
            try:
                with app_obj.app_context():
                    # 重新获取会话中的对象，避免跨线程共享同一Session
                    req_obj = db.session.get(DecorationRequest, req_id)
                    if not req_obj:
                        return
                    print(f"[Decoration] Start processing request_id={req_id}")
                    coze_service = CozeService()
                    coze_service.generate_decoration_plan(req_obj)
                    print(f"[Decoration] Finished processing request_id={req_id}, status={req_obj.status}")
                    # 确保线程内提交结束后释放连接
                    db.session.remove()
            except Exception as e:
                # 打印错误但不打断主请求
                print(f"装修方案生成失败: {str(e)}")
                try:
                    # 在出错时也尝试标记为失败，并写入错误详情，便于前端展示
                    with app_obj.app_context():
                        req_obj = db.session.get(DecorationRequest, req_id)
                        if req_obj:
                            req_obj.status = 'failed'
                            try:
                                req_obj.coze_response = json.dumps({'error': str(e)}, ensure_ascii=False)
                            except Exception:
                                req_obj.coze_response = str(e)
                            db.session.commit()
                        db.session.remove()
                except Exception:
                    pass
        
        thread = threading.Thread(target=process_decoration, args=(request_id,))
        thread.daemon = True
        thread.start()
        
        return jsonify({
            'success': True,
            'message': '装修方案生成请求已提交',
            'request_id': request_id
        })
        
    except Exception as e:
        return jsonify({'error': f'生成装修方案失败: {str(e)}'}), 500


@decoration_bp.route('/status/<int:request_id>', methods=['GET'])
def get_request_status(request_id):
    """获取装修请求状态"""
    try:
        decoration_request = DecorationRequest.query.get_or_404(request_id)
        
        response_data = {
            'request_id': decoration_request.id,
            'status': decoration_request.status,
            'created_at': decoration_request.created_at.isoformat() if decoration_request.created_at else None,
            'updated_at': decoration_request.updated_at.isoformat() if decoration_request.updated_at else None
        }
        # 始终回传原始的 coze_response，便于前端和排查
        if decoration_request.coze_response:
            try:
                response_data['coze_response'] = json.loads(decoration_request.coze_response)
            except json.JSONDecodeError:
                response_data['coze_response'] = decoration_request.coze_response
        
        if decoration_request.status == 'completed':
            # 解析响应数据
            if decoration_request.coze_response:
                try:
                    coze_data = json.loads(decoration_request.coze_response)
                    response_data['result'] = coze_data
                except json.JSONDecodeError:
                    response_data['result'] = {'raw_response': decoration_request.coze_response}
            
            # 解析生成的图片
            if decoration_request.generated_images:
                try:
                    image_urls = json.loads(decoration_request.generated_images)
                    response_data['generated_images'] = image_urls
                except json.JSONDecodeError:
                    response_data['generated_images'] = []
        
        elif decoration_request.status == 'failed':
            # 尽最大可能返回错误细节
            try:
                if decoration_request.coze_response:
                    try:
                        error_data = json.loads(decoration_request.coze_response)
                        response_data['error'] = error_data.get('error') or error_data.get('message') or str(error_data)
                    except json.JSONDecodeError:
                        response_data['error'] = decoration_request.coze_response
                else:
                    response_data['error'] = '生成失败，错误详情缺失'
            except Exception as e:
                response_data['error'] = f'生成失败（解析错误详情异常：{str(e)}）'
        
        return jsonify(response_data)
        
    except Exception as e:
        return jsonify({'error': f'获取请求状态失败: {str(e)}'}), 500


@decoration_bp.route('/requests', methods=['GET'])
@jwt_required()
def get_requests():
    """获取装修请求列表"""
    try:
        # 统一转换身份为整型
        user_identity = get_jwt_identity()
        try:
            user_id = int(user_identity)
        except (TypeError, ValueError):
            return jsonify({'error': '无效的用户身份'}), 401
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        
        requests = DecorationRequest.query.filter_by(user_id=user_id).order_by(DecorationRequest.created_at.desc()).paginate(
            page=page, per_page=per_page, error_out=False
        )
        
        return jsonify({
            'requests': [req.to_dict() for req in requests.items],
            'total': requests.total,
            'pages': requests.pages,
            'current_page': page,
            'per_page': per_page
        })
        
    except Exception as e:
        return jsonify({'error': f'获取请求列表失败: {str(e)}'}), 500


@decoration_bp.route('/styles', methods=['GET'])
def get_decoration_styles():
    """获取装修风格列表"""
    styles = [
        "现代简约", "欧式风格", "中式风格", "美式风格", 
        "日式风格", "工业风", "北欧风", "地中海风格"
    ]
    return jsonify({'styles': styles})


@decoration_bp.route('/room-types', methods=['GET'])
def get_room_types():
    """获取房间类型列表"""
    room_types = [
        "客厅", "卧室", "厨房", "卫生间", 
        "书房", "儿童房", "餐厅", "全屋"
    ]
    return jsonify({'room_types': room_types})
